﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace MathService.Vectors
{
    public class Vector<T> : IEnumerable<T>, ICloneable<Vector<T>>, IEquatable<Vector<T>>
    {
        /* ------------------------------------------------------------------------------------------ */

        private readonly T[] f_Elements;

        /* ------------------------------------------------------------------------------------------ */

        public int Demention { get { return f_Elements.Length; } }

        public T this[int i] { get { return f_Elements[i]; } set { f_Elements[i] = value; } }

        /* ------------------------------------------------------------------------------------------ */

        public Vector(int Demention) { f_Elements = new T[Demention]; }

        public Vector(T[] Elements) { f_Elements = (T[])Elements.Clone(); }

        public Vector(IEnumerable<T> Elements) : this(Elements.ToArray()) { }

        /* ------------------------------------------------------------------------------------------ */

        public override int GetHashCode()
        {
            var result = Consts.BigPrime_int;
            for(var i = 0; i < f_Elements.Length; i++)
                result ^= f_Elements.GetHashCode();
            return result;
        }

        public bool Equals(Vector<T> other)
        {
            if(ReferenceEquals(other, null)) return false;
            if(ReferenceEquals(other, this)) return true;
            if(other.Demention != Demention) return false;

            for(var i = 0; i < f_Elements.Length; i++) if(!f_Elements[i].Equals(other[i])) return false;
            return true;
        }

        public override bool Equals(object obj) { return (obj is Vector<T>) && Equals(obj as Vector<T>); }

        public Vector<T> Clone() { return new Vector<T>(f_Elements); }

        object ICloneable.Clone() { return Clone(); }


        public IEnumerator<T> GetEnumerator() { return (IEnumerator<T>)f_Elements.GetEnumerator(); }

        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

        /* ------------------------------------------------------------------------------------------ */

        public static implicit operator Vector<T>(T[] e) { return new Vector<T>(e); }

        public static implicit operator Vector<T>(List<T> e) { return new Vector<T>(e); }

        /* ------------------------------------------------------------------------------------------ */
    }
}
